﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Device.Location;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using BingleMaps.Converters;
using BingleMaps.Extensions;
using BingleMaps.Models;
using BingleMaps.Models.GoogleMaps;
using BingleMaps.Services;
using BingleMaps.ViewModels;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Phone.Controls.Maps.Platform;
using Microsoft.Phone.Shell;
using GestureEventArgs = System.Windows.Input.GestureEventArgs;
using Location = BingleMaps.Models.GoogleMaps.Location;
using Size = BingleMaps.Models.GoogleMaps.Size;
using TravelMode = BingleMaps.BingMaps.Route.TravelMode;

namespace BingleMaps
{
	public partial class MainPage
	{
		#region Private Members

		private readonly MainViewModel _mainViewModel;
		private readonly SpecialUserPinToOpacityConverter _specialUserPinToOpacityConverter = new SpecialUserPinToOpacityConverter();
		private readonly SpecialUserPinToBoolConverter _specialUserPinToBoolConverter = new SpecialUserPinToBoolConverter();
		private readonly Random _rdm = new Random();
		private Pushpin _touchedPin;
		private readonly Binding _mapViewBinding = new Binding("Settings.MapView") { Mode = BindingMode.TwoWay, Converter = (IValueConverter)Application.Current.Resources["MapViewConverter"] };
		private bool _waitingForLocation;
		private static readonly Regex _xmlTagRegex = new Regex("<[^>]+>");

		private const string STATE_Default = "Default";
		private const string STATE_Directions = "Directions";
		private const string STATE_Search = "Search";
		private const string STATE_Itinerary = "Itinerary";
		private const string STATE_PinDrop = "PinDrop";

		#endregion


		public MainPage()
		{
			InitializeComponent();
			MapModeListPicker.SetBinding(ListPicker.SelectedItemProperty, _mapViewBinding);
			_mainViewModel = (MainViewModel)DataContext;
			AppBarIconButtonCurrentLocation = (ApplicationBarIconButton)ApplicationBar.Buttons[0];
			AppBarIconButtonLayers = (ApplicationBarIconButton)ApplicationBar.Buttons[3];
			AppBarMenuItemItinerary = (ApplicationBarMenuItem)ApplicationBar.MenuItems[0];
			AppBarMenuItemSync = (ApplicationBarMenuItem)ApplicationBar.MenuItems[3];
			_mainViewModel.PropertyChanged += OnIsFollowingCurrentLocationChanged;
		}

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			GoToDefaultState();
		}

		private void AppBarIconButtonCurrentLocationClick(object sender, EventArgs e)
		{
			_mainViewModel.IsFollowingCurrentLocation = true;
			if (_mainViewModel.CurrentLocation != null && !_mainViewModel.CurrentLocation.IsUnknown)
			{
				_mainViewModel.MapCenter = _mainViewModel.CurrentLocation;
			}
			else
			{
				_waitingForLocation = ProgressBar.IsIndeterminate = true;
				_mainViewModel.PropertyChanged += OnCurrentLocationReached;
			}
		}

		private void OnCurrentLocationReached(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName != MainViewModel.CurrentLocationPropertyName || _mainViewModel.CurrentLocation == null || _mainViewModel.CurrentLocation.IsUnknown)
			{
				return;
			}
			_waitingForLocation = ProgressBar.IsIndeterminate = false;
			_mainViewModel.PropertyChanged -= OnCurrentLocationReached;
		}

		private bool _surpassMapPan;

		private bool SurpassMapPan
		{
			set
			{
				if (value == _surpassMapPan)
				{
					return;
				}
				_surpassMapPan = value;
				if (value)
				{
					Map.MapPan += CancelMapPan;
				}
				else
				{
					Map.MapPan -= CancelMapPan;
				}
			}
		}

		private static void CancelMapPan(object sender, MapDragEventArgs e)
		{
			e.Handled = true;
		}

		private void MapHold(object sender, GestureEventArgs e)
		{
			var p = e.GetPosition(Map);
			_mainViewModel.EditingUserPin = null;
			if (_touchedPin == null || ((UserPin)_touchedPin.DataContext).IsTemporary)
			{
				CatalogPushpin.Location = Map.ViewportPointToLocation(p);
				GoToState(STATE_PinDrop, true);
			}
			else
			{
				var pinP = _touchedPin.TransformToVisual(Map).Transform(new Point());
				PushpinHoldStoryboard.Stop();
				Storyboard.SetTarget(PushpinHoldAnimationY, _touchedPin);
				Storyboard.SetTarget(PushpinHoldAnimationX, _touchedPin);
				PushpinHoldAnimationX.To = p.X - pinP.X;
				PushpinHoldAnimationY.To = p.Y - pinP.Y - _touchedPin.RenderSize.Height + Globals.PinDragFloatOffsetY;
				PushpinHoldStoryboard.Begin();
				_mainViewModel.HeldUserPin = (UserPin)_touchedPin.DataContext;
			}
		}

		private void MapDragDelta(object sender, DragDeltaGestureEventArgs e)
		{
			if (_mainViewModel.HeldUserPin == null || _touchedPin == null)
			{
				return;
			}
			var trans = (TranslateTransform)_touchedPin.RenderTransform;
			trans.X += e.HorizontalChange;
			trans.Y += e.VerticalChange;
		}

		private void MapTap(object sender, GestureEventArgs e)
		{
			if (CatalogPushpin.Visibility == Visibility.Visible)
			{
				GoToDefaultState();
			}
			if (_touchedPin == null)
			{
				_mainViewModel.EditingUserPin = null;
			}
			else
			{
				var userPin = (UserPin)_touchedPin.DataContext;
				_mainViewModel.EditingUserPin = _mainViewModel.EditingUserPin != null && userPin.Key == _mainViewModel.EditingUserPin.Key ? null : userPin;
				_touchedPin = null;
			}
		}

		private void MapDragCompleted(object sender, DragCompletedGestureEventArgs e)
		{
			if (_mainViewModel.HeldUserPin == null)
			{
				return;
			}
			var pinP = _touchedPin.TransformToVisual(Map).Transform(new Point());
			pinP.Y += _touchedPin.RenderSize.Height;
			var p = _mainViewModel.HeldUserPin;
			var loc = Map.ViewportPointToLocation(pinP);
			p.Location = loc;
			var lngLat = new Location
			{
				Lat = loc.Latitude,
				Lng = loc.Longitude
			};
			var size = new Size { Width = 125, Height = 125 };
			p.Image = GoogleMapsServices.GetStaticMap(lngLat, 15, size);
			p.Address = null;
			if (Globals.IsNetworkAvailable)
			{
				GoogleMapsServices.ReverseGeocode(lngLat, places =>
				{
					if (places == null || places.Count() == 0)
					{
						return;
					}
					p.Address = places.First().FormattedAddress;
				});
				p.Image = GoogleMapsServices.GetStaticMap(lngLat, 15, size);
			}
			var trans = (TranslateTransform)_touchedPin.RenderTransform;
			trans.X = trans.Y = default(double);
			_mainViewModel.HeldUserPin.IsMoving = false;
			_mainViewModel.HeldUserPin = null;
			_mainViewModel.EditingUserPin = (UserPin)_touchedPin.DataContext;
			_touchedPin = null;
			SurpassMapPan = false;
		}

		private void MapDragStarted(object sender, DragStartedGestureEventArgs e)
		{
			if (_mainViewModel.HeldUserPin == null || _touchedPin == null)
			{
				return;
			}
			SurpassMapPan = true;
			_mainViewModel.HeldUserPin.IsMoving = true;
		}

		private void MapRelease(object sender, MouseButtonEventArgs e)
		{
			if (_touchedPin == null || _mainViewModel.HeldUserPin == null || _mainViewModel.HeldUserPin.IsMoving)
			{
				return;
			}
			PushpinHoldAnimationX.To = PushpinHoldAnimationY.To = 0D;
			PushpinHoldStoryboard.Begin();
			_mainViewModel.HeldUserPin = null;
			_touchedPin = null;
		}

		private void UserPushpinRemoveButtonClick(object sender, GestureEventArgs e)
		{
			_mainViewModel.UserPinLog.Remove(((UserPin)((FrameworkElement)sender).DataContext).Key);
			_mainViewModel.EditingUserPin = null;
		}

		private void MapMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			var p = e.GetPosition(null);
			foreach (var elm in VisualTreeHelper.FindElementsInHostCoordinates(p, UserPushpinLayer))
			{
				if (elm is Pushpin)
				{
					_touchedPin = (Pushpin)elm;
					return;
				}
			}
			foreach (var elm in VisualTreeHelper.FindElementsInHostCoordinates(p, FixedPushpinLayer))
			{
				if (elm is Pushpin)
				{
					_touchedPin = (Pushpin)elm;
					return;
				}
			}
			_touchedPin = null;
		}

		private void UserPushpinDirectionFromPinButtonClick(object sender, GestureEventArgs e)
		{
			if (_mainViewModel.EditingUserPin.Address == null)
			{
				_mainViewModel.FromDirectionPoint.Input = _mainViewModel.EditingUserPin.Location.ToString();
			}
			else
			{
				_mainViewModel.FromDirectionPoint.Input = _mainViewModel.EditingUserPin.Address;
				_mainViewModel.FromDirectionPoint.Location = _mainViewModel.EditingUserPin.Location;
			}
			GoToState(STATE_Directions);
			FromTextBox.Focus();
		}

		private void CancelMouseButtonEvent(object sender, MouseButtonEventArgs e)
		{
			e.Handled = true;
		}

		private void UserPushpinDirectionToPinButtonClick(object sender, GestureEventArgs e)
		{
			if (_mainViewModel.EditingUserPin.Address == null)
			{
				_mainViewModel.ToDirectionPoint.Input = _mainViewModel.EditingUserPin.Location.ToString();
			}
			else
			{
				_mainViewModel.ToDirectionPoint.Input = _mainViewModel.EditingUserPin.Address;
				_mainViewModel.ToDirectionPoint.Location = _mainViewModel.EditingUserPin.Location;
			}
			GoToState(STATE_Directions);
			ToTextBox.Focus();
		}

		private void OnGetDirections(object sender, RoutedEventArgs e)
		{
			GetDirections();
		}

		private void GetDirections()
		{
			if ((_mainViewModel.FromDirectionPoint.IsCurrentLocation || _mainViewModel.ToDirectionPoint.IsCurrentLocation) && (_mainViewModel.CurrentLocation == null || _mainViewModel.CurrentLocation.IsUnknown))
			{
				MessageBox.Show("Your current location is unavailable at the moment. Please try again later.", "No Current Location", MessageBoxButton.OK);
				return;
			}
			GoToDefaultState();
			var from = _mainViewModel.FromDirectionPoint;
			var to = _mainViewModel.ToDirectionPoint;
			if (from.IsCurrentLocation)
			{
				from.Location = _mainViewModel.CurrentLocation;
			}
			if (to.IsCurrentLocation)
			{
				to.Location = _mainViewModel.CurrentLocation;
			}
			ProgressBar.IsIndeterminate = true;
			BingMapsServices.GetDirections(_mainViewModel.FromDirectionPoint, _mainViewModel.ToDirectionPoint, (Rectangle)Map.BoundingRectangle, _mainViewModel.Settings.IsWalking ? TravelMode.Walking : TravelMode.Driving, routeResult =>
			{
				ProgressBar.IsIndeterminate = false;
				if (routeResult == null || routeResult.RoutePath.Points.Count == 0)
				{
					MessageBox.Show("There was a problem finding directions for you. Please make sure your \"From\" and \"To\" locations are valid and you are connected to the Internet.", "Unable To Find Directions", MessageBoxButton.OK);
					return;
				}
				var itineraries = new Collection<ItineraryItem>();
				foreach (var item in routeResult.Legs[0].Itinerary)
				{
					itineraries.Add(
						new ItineraryItem
						{
							Distance = item.Summary.Distance,
							Instruction = _xmlTagRegex.Replace(item.Text, string.Empty),
							Location = item.Location
						});
				}
				_mainViewModel.Itineraries = itineraries;
				_mainViewModel.RouteLocations = routeResult.RoutePath.Points;
				Map.SetView(LocationRect.CreateLocationRect(MapPolyline.Locations));
				_mainViewModel.EditingUserPin = null;
				AppBarMenuItemItinerary.IsEnabled = true;
				if (_mainViewModel.FromDirectionPoint.IsCurrentLocation)
				{
					_mainViewModel.FromDirectionPoint.Location = null;
				}
				if (_mainViewModel.ToDirectionPoint.IsCurrentLocation)
				{
					_mainViewModel.ToDirectionPoint.Location = null;
				}
			});
		}

		private void AppBarIconButtonDirectionsClick(object sender, EventArgs e)
		{
			GoToState(STATE_Directions);
			FromTextBox.Focus();
		}

		private void AppBarIconButtonSearchClick(object sender, EventArgs e)
		{
			GoToState(STATE_Search);
			SearchBox.Focus();
		}

		private void BeginSearch()
		{
			if (string.IsNullOrEmpty(_mainViewModel.SearchQuery.Input))
			{
				return;
			}
			GoToDefaultState();
			ProgressBar.IsIndeterminate = true;
			_mainViewModel.TemporaryPins.Clear();

			if (_mainViewModel.SearchQuery.SelectedSuggestion == null)
			{
				GoogleMapsServices.SearchPlaces(
					new Location { Lat = Map.Center.Latitude, Lng = Map.Center.Longitude },
					_mainViewModel.SearchQuery.Input,
					10,
					placesResults =>
					{
						if (placesResults == null || placesResults.Count() == 0)
						{
							GoogleMapsServices.Geocode(
								_mainViewModel.SearchQuery.Input,
								new ViewPort
								{
									SouthWest = new Location { Lat = Map.BoundingRectangle.South, Lng = Map.BoundingRectangle.West },
									NorthEast = new Location { Lat = Map.BoundingRectangle.North, Lng = Map.BoundingRectangle.East }
								},
								geoCodeResults =>
								{
									if (geoCodeResults == null || geoCodeResults.Count() == 0)
									{
										ProgressBar.IsIndeterminate = false;
										MessageBox.Show("The search did not find any results. Please make sure that you are connected to the Internet. Otherwise, try refining your keywords and try again.", "Nothing Was Found", MessageBoxButton.OK);
										return;
									}
									ShowSearchResults(geoCodeResults.OfType<Place>());
								});
						}
						else
						{
							ShowSearchResults(placesResults);
						}
					});
			}
			else
			{
				GoogleMapsServices.GetPlaceDetails(_mainViewModel.SearchQuery.SelectedSuggestion.Reference, details =>
				{
					if (details == null)
					{
						ProgressBar.IsIndeterminate = false;
						MessageBox.Show("The search did not find any results. Please make sure that you are connected to the Internet. Otherwise, try refining your keywords and try again.", "Nothing Was Found", MessageBoxButton.OK);
						return;
					}
					ShowSearchResult(details);
				});
			}
		}

		private void ShowSearchResult(Place place)
		{
			ProgressBar.IsIndeterminate = false;
			_mainViewModel.EditingUserPin = null;
			int colorIndex = _rdm.Next(SettingsViewModel.AvailablePushpinColors.Count - 1), i = 0;
			var color = SettingsViewModel.AvailablePushpinColors[SettingsViewModel.AvailablePushpinColors.Keys.First(key => i++ == colorIndex)];
			var p = new UserPin
			{
				Location = new Microsoft.Phone.Controls.Maps.Platform.Location { Latitude = place.Geometry.Location.Lat, Longitude = place.Geometry.Location.Lng },
				Title = string.IsNullOrEmpty(place.Name) ? "My Search" : place.Name,
				IsTemporary = true,
				Color = color,
				Key = Guid.NewGuid()
			};
			if (place is PlaceDetails)
			{
				p.Address = ((PlaceDetails)place).FormattedAddress;
			}
			else if (Globals.IsNetworkAvailable)
			{
				GoogleMapsServices.ReverseGeocode(
					place.Geometry.Location,
					reverseGeocodeResults =>
					{
						if (reverseGeocodeResults != null && reverseGeocodeResults.Count() > 0)
						{
							p.Address = reverseGeocodeResults.First().FormattedAddress;
						}
					});
			}

			p.Image = GoogleMapsServices.GetStaticMap(
				new Location { Lat = p.Location.Latitude, Lng = p.Location.Longitude },
				15,
				new Size { Width = 125, Height = 125 });
			_mainViewModel.TemporaryPins.Add(p);

			var viewPort = place.Geometry.ViewPort;
			if (viewPort == null)
			{
				var l = place.Geometry.Location;
				Map.SetView(new GeoCoordinate(l.Lat, l.Lng), 15);
			}
			else
			{
				Map.SetView(new LocationRect(viewPort.NorthEast.Lat, viewPort.SouthWest.Lng, viewPort.SouthWest.Lat, viewPort.NorthEast.Lng));
			}
		}

		private void ShowSearchResults(IEnumerable<Place> places)
		{
			ProgressBar.IsIndeterminate = false;
			_mainViewModel.EditingUserPin = null;
			var collection = new LocationCollection();
			int colorIndex = _rdm.Next(SettingsViewModel.AvailablePushpinColors.Count - 1), i = 0;
			var color = SettingsViewModel.AvailablePushpinColors[SettingsViewModel.AvailablePushpinColors.Keys.First(key => i++ == colorIndex)];

			foreach (var l in places)
			{
				var p = new UserPin
				{
					Location = new Microsoft.Phone.Controls.Maps.Platform.Location { Latitude = l.Geometry.Location.Lat, Longitude = l.Geometry.Location.Lng },
					Title = string.IsNullOrEmpty(l.Name) ? "My Search" : l.Name,
					IsTemporary = true,
					Color = color,
					Key = Guid.NewGuid()
				};

				if (l is PlaceDetails)
				{
					p.Address = ((PlaceDetails)l).FormattedAddress;
				}
				else if (Globals.IsNetworkAvailable)
				{
					GoogleMapsServices.ReverseGeocode(
						l.Geometry.Location,
						reverseGeocodeResults =>
						{
							if (reverseGeocodeResults != null && reverseGeocodeResults.Count() > 0)
							{
								p.Address = reverseGeocodeResults.First().FormattedAddress;
							}
						});
				}

				p.Image = GoogleMapsServices.GetStaticMap(
					new Location { Lat = p.Location.Latitude, Lng = p.Location.Longitude },
					15,
					new Size { Width = 125, Height = 125 });
				_mainViewModel.TemporaryPins.Add(p);
				if (l.Geometry.ViewPort == null)
				{
					collection.Add(p.Location);
				}
				else
				{
					var viewPort = l.Geometry.ViewPort;
					collection.Add(new GeoCoordinate(viewPort.NorthEast.Lat, viewPort.NorthEast.Lng));
					collection.Add(new GeoCoordinate(viewPort.SouthWest.Lat, viewPort.SouthWest.Lng));
				}
			}
			Map.SetView(LocationRect.CreateLocationRect(collection));
		}

		private void AppBarMenuItemClearSearchClick(object sender, EventArgs e)
		{
			if (_mainViewModel.TemporaryPins.Contains(_mainViewModel.EditingUserPin))
			{
				_mainViewModel.EditingUserPin = null;
			}
			_mainViewModel.TemporaryPins.Clear();
		}

		private void TemporaryPushpinPinButtonClick(object sender, GestureEventArgs e)
		{
			var pin = (UserPin)((FrameworkElement)sender).DataContext;
			pin.IsTemporary = false;
			_mainViewModel.TemporaryPins.Remove(pin);
			_mainViewModel.UserPinLog.Add(pin);
		}

		private void SetFromLocationToCurrentLocationHyperlinkButtonClick(object sender, RoutedEventArgs e)
		{
			if (_mainViewModel.CurrentLocation == null || _mainViewModel.CurrentLocation.IsUnknown)
			{
				MessageBox.Show("Your current location is unavailable at the moment. Please try again later.", "No Current Location", MessageBoxButton.OK);
				return;
			}
			_mainViewModel.FromDirectionPoint.Input = DirectionPoint.CurrentLocationString;
		}

		private void SetToLocationToCurrentLocationHyperlinkButtonClick(object sender, RoutedEventArgs e)
		{
			if (_mainViewModel.CurrentLocation == null || _mainViewModel.CurrentLocation.IsUnknown)
			{
				MessageBox.Show("Your current location is unavailable at the moment. Please try again later.", "No Current Location", MessageBoxButton.OK);
				return;
			}
			_mainViewModel.ToDirectionPoint.Input = DirectionPoint.CurrentLocationString;
		}

		private void UserPushpinLoaded(object sender, RoutedEventArgs e)
		{
			var element = ((FrameworkElement)sender);
			element.SetBinding(OpacityProperty, new Binding("EditingUserPin") { Source = _mainViewModel, Converter = _specialUserPinToOpacityConverter, ConverterParameter = element.DataContext });
			element.SetBinding(IsHitTestVisibleProperty, new Binding("EditingUserPin") { Source = _mainViewModel, Converter = _specialUserPinToBoolConverter, ConverterParameter = element.DataContext });
		}

		private void AppBarMenuItemClearRouteClick(object sender, EventArgs e)
		{
			_mainViewModel.RouteLocations = null;
			_mainViewModel.Itineraries = null;
			AppBarMenuItemItinerary.IsEnabled = false;
		}

		private void ZoomInButtonClick(object sender, RoutedEventArgs e)
		{
			Map.ZoomLevel++;
		}

		private void ZoomOutButtonClick(object sender, RoutedEventArgs e)
		{
			Map.ZoomLevel--;
		}

		private void GoToState(string name, bool isApplicationBarVisible = false)
		{
			BackKeyPress -= BackToDefaultState;
			BackKeyPress += BackToDefaultState;
			ApplicationBar.IsVisible = isApplicationBarVisible;
			VisualStateManager.GoToState(this, name, true);
		}

		private void BackToDefaultState(object sender, CancelEventArgs e)
		{
			e.Cancel = true;
			GoToDefaultState();
		}

		private void GoToDefaultStateButtonEvent(object sender, MouseButtonEventArgs e)
		{
			GoToDefaultState();
		}

		private void GoToDefaultState()
		{
			BackKeyPress -= BackToDefaultState;
			VisualStateManager.GoToState(this, STATE_Default, true);
			ApplicationBar.IsVisible = true;
			Focus();
		}

		private void AppBarIconButtonLayersClick(object sender, EventArgs e)
		{
			NavigationService.Navigate(new Uri("/Views/LayersView.xaml", UriKind.Relative));
		}

		private void ItineraryContentSelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (e.AddedItems.Count == 0)
			{
				return;
			}
			var item = (KeyValuePair<UInt16, ItineraryItem>)e.AddedItems[0];
			Map.SetView(item.Value.Location, 16D);
		}

		private void CurrentLocationPushpinTap(object sender, GestureEventArgs e)
		{
			e.Handled = true;
			CatalogPushpin.Location = CurrentLocationPushpin.Location;
			GoToState(STATE_PinDrop, true);
		}

		private void AppBarMenuItemSyncClick(object sender, EventArgs e)
		{
			ProgressBar.IsIndeterminate = true;
			AppBarMenuItemSync.IsEnabled = false;
			if (_mainViewModel.Settings.DropNetUserLogin == null)
			{
				NavigationService.Navigate(new Uri("/Views/DropBoxView.xaml", UriKind.Relative));
			}
			else
			{
				Sync();
			}
		}

		private void Sync()
		{
			DropBoxServices.Sync(_mainViewModel.Settings.DropNetUserLogin, _mainViewModel.UserPinLog,
								 status =>
								 {
									 ProgressBar.IsIndeterminate = false;
									 AppBarMenuItemSync.IsEnabled = true;
									 MessageBox.Show("Your data has been synchronised successfully.", "Sync Successful", MessageBoxButton.OK);
								 },
								 ex =>
								 {
									 ProgressBar.IsIndeterminate = false;
									 AppBarMenuItemSync.IsEnabled = true;
									 MessageBox.Show("There was a problem syncing your data, please try again later.", "Sync Failed", MessageBoxButton.OK);
								 });
		}

		private void AppBarMenuItemMoreClick(object sender, EventArgs e)
		{
			NavigationService.Navigate(new Uri("/Views/MoreView.xaml", UriKind.Relative));
		}

		private void PhoneApplicationPageLoaded(object sender, RoutedEventArgs e)
		{
			if (_mainViewModel.Settings.IsFirstTime)
			{
				_mainViewModel.Settings.EnableLocationService = MessageBox.Show(Application.Current.Resources["PrivacyPolicyText"].ToString(), "Location Service", MessageBoxButton.OKCancel) == MessageBoxResult.OK;
				_mainViewModel.Settings.IsFirstTime = false;
			}
			AppBarMenuItemSync.IsEnabled = _mainViewModel.Settings.Sync;
			AppBarIconButtonCurrentLocation.IsEnabled = _mainViewModel.Settings.EnableLocationService;
			AppBarMenuItemItinerary.IsEnabled = _mainViewModel.Itineraries != null;
			ZoomBar.Visibility = _mainViewModel.Settings.ShowZoomBar ? Visibility.Visible : Visibility.Collapsed;
			Map.AnimationLevel = _mainViewModel.Settings.UseMapAnimation ? AnimationLevel.Full : AnimationLevel.UserInput;
		}

		private void AppBarMenuItemItineraryClick(object sender, EventArgs e)
		{
			GoToState(STATE_Itinerary);
		}

		private void DirectionTextBoxTextChanged(object sender, RoutedEventArgs e)
		{
			ShowDirectionsButton.IsEnabled = !string.IsNullOrEmpty(FromTextBox.Text) && !string.IsNullOrEmpty(ToTextBox.Text);
		}

		private void CatelogPushpinHyperlinkButtonClick(object sender, RoutedEventArgs e)
		{
			var p = new UserPin
			{
				Location = CatalogPushpin.Location,
				Display = ((Microsoft.Phone.Controls.Maps.Platform.Location)CatalogPushpin.Location).ToLatLngString(),
				Icon = ((KeyValuePair<string, string>)((FrameworkElement)sender).DataContext).Value,
				Image = GoogleMapsServices.GetStaticMap(
					new Location { Lat = CatalogPushpin.Location.Latitude, Lng = CatalogPushpin.Location.Longitude },
					15,
					new Size { Width = 125, Height = 125 })
			};
			if (Globals.IsNetworkAvailable)
			{
				BingMapsServices.GetAddress(p.Location, result =>
				{
					if (result != null)
					{
						p.Address = result.Address.FormattedAddress;
					}
				});
			}
			_mainViewModel.UserPinLog.Add(p);
			GoToDefaultState();
		}

		public void OnIsFollowingCurrentLocationChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName != MainViewModel.IsFollowingCurrentLocationPropertyName)
			{
				return;
			}
			AppBarIconButtonCurrentLocation.IsEnabled = !_mainViewModel.IsFollowingCurrentLocation;
			if (_mainViewModel.IsFollowingCurrentLocation || !_waitingForLocation)
			{
				return;
			}
			_waitingForLocation = ProgressBar.IsIndeterminate = false;
			_mainViewModel.PropertyChanged -= OnCurrentLocationReached;
		}

		private void OnSearch(object sender, EventArgs e)
		{
			BeginSearch();
		}
	}
}
